﻿using System;
using System.ComponentModel;
using System.Drawing;
using System.Runtime.CompilerServices;
using System.Windows.Forms;
using DriveBeamEditor.Annotations;
using DriveBeamEditor.Interfaces;
using DriveBeamEditor.Tools;

namespace DriveBeamEditor.Controls.General
{
    public partial class KeyValueControl : UserControl, IEditor, INotifyPropertyChanged
    {
        #region Fields

        private string _key;
        private int _minCaptionWidth = 125;
        private bool _editable = true;

        public event EventHandler KeyChanged;
        public event EventHandler ValueChanged;
        public event EventHandler EditValueChanged;
        public event EventHandler EditableChanged;
        public event EventHandler<int> MinCaptionWidthChanged;

        #endregion

        #region Properties

        public int MinCaptionWidth
        {
            get { return _minCaptionWidth; }
            set
            {
                if (value == _minCaptionWidth) return;

                _minCaptionWidth = value;
                UpdateCaptionSize();

                if (MinCaptionWidthChanged != null)
                    MinCaptionWidthChanged(this, value);
            }
        }

        public string Caption
        {
            get { return labelKey.Text; }
            set
            {
                if (labelKey.Text.Equals(value)) return;

                labelKey.Text = value;

                UpdateCaptionSize();
            }
        }

        public string Key
        {
            get { return _key; }
            set
            {
                if (_key == value) return;

                _key = value;

                OnKeyChanged();
            }
        }

        public string Value
        {
            get { return editor.EditValue != null ? editor.EditValue.ToString() : null; }
            set
            {
                if (Value == value) return;

                editor.EditValue = UIHelper.ValueFromString(value);

                OnValueChanged();
            }
        }

        public object EditValue
        {
            get { return editor.EditValue; }
            set
            {
                editor.EditValue = value;
                OnPropertyChanged();
            }
        }

        public bool ReadOnly
        {
            get { return editor.Enabled; }
            set { editor.Enabled = value; }
        }

        public bool Editable
        {
            get { return _editable; }
            set
            {
                if (_editable == value) return;
                _editable = value;
                OnEditableChanged();
            }
        }

        public Editor Editor
        {
            get { return editor; }
            internal set { editor = value; }
        }

        #endregion

        #region CTORs

        public KeyValueControl()
        {
            InitializeComponent();
            InitializeDefaults();
            Dock = DockStyle.Top;
            UpdateCaptionSize();
        }

        #endregion

        #region Events

        private void labelKey_FontChanged(object sender, EventArgs e)
        {
            UpdateCaptionSize();
        }

        private void editor_EditValueChanged(object sender, EventArgs e)
        {
            if (EditValueChanged != null)
                EditValueChanged(this, e);
        }

        protected override void OnEnabledChanged(EventArgs e)
        {
            if (!Editable && Enabled)
                Enabled = false;
            else
                base.OnEnabledChanged(e);
        }

        #endregion

        #region Methods

        private void InitializeDefaults()
        {
            Key = "Key";
            Caption = "Key";
            Value = "Value";
        }

        private void UpdateCaptionSize()
        {
            var g = labelKey.CreateGraphics();
            var sz = g.MeasureString(labelKey.Text, labelKey.Font, PointF.Empty,
                new StringFormat(StringFormatFlags.NoClip | StringFormatFlags.NoWrap));
            labelKey.Width = Math.Max(MinCaptionWidth,
                (int)Math.Ceiling(sz.Width) +
                labelKey.Padding.Left +
                labelKey.Padding.Right +
                labelKey.Margin.Left +
                labelKey.Margin.Right
            );
        }

        private void OnKeyChanged()
        {
            if (KeyChanged != null)
                KeyChanged(this, new EventArgs());
        }

        private void OnValueChanged()
        {
            if (ValueChanged != null)
                ValueChanged(this, new EventArgs());
        }

        private void OnEditableChanged()
        {
            if (!Editable && Enabled) Enabled = false;

            if (EditableChanged != null)
                EditableChanged(this, new EventArgs());
        }

        public void SetEditValueSilent(object value)
        {
            editor.SetEditValueSilent(value);
        }

        #endregion

        #region INotifyPropertyChanged

        public event PropertyChangedEventHandler PropertyChanged;

        [NotifyPropertyChangedInvocator]
        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            var handler = PropertyChanged;
            if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
        }

        #endregion
    }
}
